package com.hui.platform.falseworkapi.common.spring;

import com.hui.platform.falseworkapi.common.log.WebLogAspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author hui
 * @date 2020/04/29 23:06
 */
@Configuration
//开启异步
@EnableAsync
@EnableScheduling
public class ThreadConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数
        executor.setCorePoolSize(5);
        //线程池最大线程数，表示在线程池中最多能创建多少个线程
        executor.setMaxPoolSize(20);
        //队列容量
        executor.setQueueCapacity(30);
        //线程存活的时间：表示线程没有任务执行时最多保持多久时间会终止，然后线程池的数目维持在corePoolSize 大小
        executor.setKeepAliveSeconds(300);
        //拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        //在使用void返回类型的异步方法执行期间抛出异常时要使用的实例
        //@Async 的方法在独立线程调用，不能被@ControllerAdvice全局异常处理器捕获，所以需要自己设置异常处理
        return new MyAsyncUncaughtExceptionHandler() {
            @Override
            public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
                super.handleUncaughtException(throwable, method, objects);
            }
        };
    }

    private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    abstract class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
        @Override
        public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
            logger.warn("class#method: " + method.getDeclaringClass().getName() + "#" + method.getName());
            logger.warn("type        : " + throwable.getClass().getName());
            logger.error("exception   : " + throwable.getMessage());
        }
    }
}
